#!/usr/bin/env python
'''Mandrill

Usage:
    mandrill setup
    mandrill [-v] ping [--count=<cnt>]
    mandrill [-v] send [--from=<addr>] [--to=<addr>] [--subject=<subj>] [--text-only]
    mandrill [-v] search [--json] <query>
    mandrill --help

Options:
    -h --help           Show this screen.
    -v                  Turn on verbose mode - all traffic to the API will be logged to STDERR
    -V --version        Show version.
    -c --count=<cnt>    The number of times to ping Mandrill.
    -f --from=<addr>    The from address of the message to send.
    -t --to=<addr>      The recipient address of the message to send.
    -s --subject=<subj> The subject line of the message to send.
    --text-only         The message will be sent as plain-text.  If this option is not provided, HTML is presumed.
    -j --json           Print the result as a JSON string
'''
import mandrill, docopt, time, sys, os.path, socket, math, re, subprocess, tempfile
try:
    import json as json
except:
    import simplejson as json

email_re = re.compile(r'^[^\"\s@<>(),]+@[a-z0-9][a-z0-9\.\-_]*\.[a-z]+$', re.I)

def command_setup(args):
    global m
    apikey = raw_input('Your Mandrill API Key: ')
    try:
        m = mandrill.Mandrill(apikey)
        m.users.ping()
    except mandrill.Error, e:
        print('Got an error trying to use that API key: %s' % e)
        sys.exit(1)
    
    try:
        f = open('/etc/mandrill.key', 'w')
        f.write(apikey)
        f.close()
        print('Saved Mandrill API Key to /etc/mandrill.key')
    except:
        f = open(os.path.expanduser('~/.mandrill.key'), 'w')
        f.write(apikey)
        f.close()
        print('Saved Mandrill API Key to %s' % os.path.expanduser('~/.mandrill.key'))


def command_ping(args):
    print('PING https://mandrillapp.com/api/1.0/users/ping2.json')
    if args['--count'] is None:
        args['--count'] = 4
    else:
        args['--count'] = int(args['--count'])
    
    times = []
    error_count = 0
    for i in range(args['--count']):
        start = time.time()
        try:
            m.users.ping2()
            (remote_addr, remote_port) = m.last_request['remote_addr']
            reverse_addr = socket.gethostbyaddr(remote_addr)[0]
            times.append(m.last_request['time'] * 1000)

            print('%d bytes from %s (%s): req=%s port=%s time=%.2fms' % (len(m.last_request['response_body']), reverse_addr, remote_addr, i + 1, remote_port, m.last_request['time'] * 1000))
        except mandrill.Error, e:
            error_count += 1
            (remote_addr, remote_port) = m.last_request['remote_addr']
            reverse_addr = socket.gethostbyaddr(remote_addr)[0]
            times.append(m.last_request['time'] * 1000)
            
            print('%d bytes from %s (%s): req=%s port=%s time=%.2fms ERROR: %s' % (len(m.last_request['response_body']), reverse_addr, remote_addr, i + 1, remote_port, m.last_request['time'] * 1000, e))

        if i < args['--count'] - 1: time.sleep(1)
    
    sq_sum = sum([t * t for t in times])
    mean = sum(times) / len(times)
    stdev = math.sqrt((sq_sum / len(times)) - (mean * mean))
    print('\n--- Mandrill ping statistics ---')
    print('%d calls transmitted, %d received, %d%% error rate, time %dms' % (args['--count'], args['--count'] - error_count, float(error_count) / args['--count'] * 100, sum(times)))
    print('rtt min/avg/max/mdev = %.3f/%.3f/%.3f/%.3f ms' % (min(times), mean, max(times), stdev))


def command_send(args):
    if args['--from'] is not None and not email_re.match(args['--from']):
        args['--from'] = None

    if args['--to'] is not None and not email_re.match(args['--to']):
        args['--to'] = None

    while args['--from'] is None:
        from_email = raw_input('From: ').strip()
        if email_re.match(from_email):
            args['--from'] = from_email
        else:
            print('Invalid email address. Try again.')

    while args['--to'] is None:
        to_email = raw_input('To: ').strip()
        if email_re.match(to_email):
            args['--to'] = to_email
        else:
            print('Invalid email address. Try again.')

    while args['--subject'] is None:
        subject = raw_input('Subject: ').strip()
        if subject != '':
            args['--subject'] = subject
        else:
            print('Enter a subject line.')

    if sys.stdin.isatty():
        editor = os.environ.get('EDITOR', 'vim')
        if args['--text-only']:
            suffix = '.txt'
        else:
            suffix = '.html'

        with tempfile.NamedTemporaryFile(suffix=suffix) as tmp:
            if args['--text-only']:
                tmp.write('REMOVE this and replace with your text content.')
            else:
                tmp.write('<p>REMOVE this and replace with your HTML content.</p>')
            tmp.flush()

            subprocess.check_call([editor, tmp.name])
            tmp.seek(0)
            content = tmp.read()
            if 'REMOVE this and replace with your' in content:
                print('Send canceled')
                sys.exit(1)
    else:
        content = sys.stdin.read()

    msg = {'from_email': args['--from'], 'to': [{'email': args['--to']}], 'subject': args['--subject']}
    if args['--text-only']:
        msg['text'] = content
    else:
        msg['html'] = content

    m.messages.send(msg)


def command_search(args):
    query = args['<query>']
    results = m.messages.search(query)
    if args['--json']:
        json.dump(results, sys.stdout)
    else:
        print('Time\tStatus\tSender\tEmail\tSubject\tOpens\tClicks')
        for result in results:
            print('%s\t%s\t%s\t%s\t%s\t%s\t%s' % (time.strftime('%d/%b/%Y %H:%M:%S %Z', time.localtime(result['ts'])), result['state'], result['sender'], result['email'], result['subject'], result['opens'], result['clicks']))


if __name__  == '__main__':
    arguments = docopt.docopt(__doc__, version='Mandrill 1.0')
    if not arguments['setup']:
        try:
            m = mandrill.Mandrill(debug=arguments['-v'])
        except mandrill.Error:
            print('This looks like the first time you\'ve run Mandrill, so let\'s get you set up.')
            command_setup(arguments)

    commands = dict([(k[8:], getattr(sys.modules['__main__'], k)) for k in dir(sys.modules['__main__']) if k.startswith('command_')])
    for command, func in commands.items():
        if command in arguments and arguments[command]:
            try:
                func(arguments)
                sys.exit(0)
            except Exception, e:
                print(e)
                sys.exit(1)
